package com.csap.framework.oauth2.client.feign;

import cn.dev33.satoken.LoginUtil;
import cn.dev33.satoken.config.SaTokenConfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.csap.framework.oauth2.client.Oauth2ClientProperties;
import com.csap.framework.util.Assert;
import com.csap.framework.util.FinalConfigParam;
import com.csap.framework.util.StringUtil;
import com.csap.mybatisplus.core.toolkit.StringPool;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author ycf
 * @Date 2021/9/23 3:21 下午
 * @Version 1.0
 */
@Slf4j
@Order(1)
public class ClientRequestInterceptor implements RequestInterceptor {
    private final Oauth2ClientProperties clientProperties;
    /**
     * token配置
     */
    private final SaTokenConfig saTokenConfig;
    private static final String GET_USERINFO = "getUserinfo";
    /**
     * 客户端信息存储
     */
    private final Map<String, String> clientMap = new HashMap<>(16);
    private final ObjectMapper objectMapper;

    public ClientRequestInterceptor(Oauth2ClientProperties clientProperties, SaTokenConfig saTokenConfig, ObjectMapper objectMapper) {
        this.clientProperties = clientProperties;
        this.saTokenConfig = saTokenConfig;
        this.objectMapper = objectMapper;
        clientMap.put("clientId", clientProperties.getClientId());
        clientMap.put("clientSecret", clientProperties.getClientSecret());
        clientMap.put("client_id", clientProperties.getClientId());
        clientMap.put("client_secret", clientProperties.getClientSecret());
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        String platform = null;
        String loginType = null;
        String userType = null;
        if (log.isDebugEnabled()) {
            log.debug("requestTemplate url:{},method:{}", requestTemplate.url(), requestTemplate.method());
        }
        if (!requestTemplate.method().equalsIgnoreCase(HttpMethod.GET.name()) && requestTemplate.body() != null) {
            String string = new String(requestTemplate.body());
            if (StringUtil.isNotEmpty(string) && string.startsWith(StringPool.LEFT_BRACE)) {
                JSONObject jsonObject = JSON.parseObject(string);
                platform = jsonObject.getString(LoginUtil.PLATFORM);
                loginType = jsonObject.getString(LoginUtil.LOGIN_TYPE);
                userType = jsonObject.getString(LoginUtil.USER_TYPE);
                clientMap.entrySet().stream().filter(i -> !jsonObject.containsKey(i.getKey())).forEach(i -> {
                    jsonObject.put(i.getKey(), i.getValue());
                });
                requestTemplate.body(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
            }
        }
        if (HttpMethod.GET.name().equalsIgnoreCase(requestTemplate.method())) {
            try {
                if (null != requestTemplate.body()) {
                    if (log.isDebugEnabled()) {
                        log.debug("request body{}", new String(requestTemplate.body()));
                    }
                    JsonNode jsonNode = objectMapper.readTree(requestTemplate.body());
                    requestTemplate.body(null, FinalConfigParam.DEFAULT_CHARSET);
                    Map<String, Collection<String>> queries = new HashMap<>(16);
                    buildQuery(jsonNode, "", queries);
                    requestTemplate.queries(queries);
                }
            } catch (IOException e) {
                log.error("【拦截GET请求方式】-出错了：{},error:{}", e.getMessage(), e);
                throw new RuntimeException();
            }
        }
        Map<String, Collection<String>> queries = requestTemplate.queries();
        clientMap.entrySet().stream().filter(i -> !queries.containsKey(i.getKey())).forEach(i -> {
            requestTemplate.query(i.getKey(), i.getValue());
        });
        if (queries.containsKey(LoginUtil.PLATFORM) && StringUtil.isEmpty(platform)) {
            platform = new ArrayList<>(queries.get(LoginUtil.PLATFORM)).get(0);
        }
        if (queries.containsKey(LoginUtil.USER_TYPE) && StringUtil.isEmpty(userType)) {
            userType = new ArrayList<>(queries.get(LoginUtil.USER_TYPE)).get(0);
        }
        if (queries.containsKey(LoginUtil.LOGIN_TYPE) && StringUtil.isEmpty(loginType)) {
            loginType = new ArrayList<>(queries.get(LoginUtil.LOGIN_TYPE)).get(0);
        }
        if (StringUtil.isEmpty(platform)) {
            platform = clientProperties.getPlatform();
        }
        if (StringUtil.isEmpty(loginType)) {
            loginType = clientProperties.getLoginType();
        }
        if (StringUtil.isEmpty(userType)) {
            userType = clientProperties.getUserType();
        }
        if (requestTemplate.path().endsWith(GET_USERINFO)) {
            requestTemplate.query(saTokenConfig.getTokenName(), LoginUtil.getInstance().getTokenValue());
            requestTemplate.header(saTokenConfig.getTokenName(), LoginUtil.getInstance().getTokenValue());
        }
        Assert.notEmpty(loginType, "登录类型未配置");
        requestTemplate.header(saTokenConfig.getLoginType(), loginType);
        Assert.notEmpty(userType, "用户类型未配置");
        requestTemplate.header(LoginUtil.USER_TYPE, userType);
        if (StringUtil.isNotEmpty(platform)) {
            requestTemplate.header(LoginUtil.PLATFORM, platform);
        }
    }

    private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
        // 叶子节点
        if (!jsonNode.isContainerNode()) {
            if (jsonNode.isNull()) {
                return;
            }
            Collection<String> values = queries.computeIfAbsent(path, k -> new ArrayList<>());
            values.add(jsonNode.asText());
            return;
        }
        // 数组节点
        if (jsonNode.isArray()) {
            Iterator<JsonNode> it = jsonNode.elements();
            while (it.hasNext()) {
                buildQuery(it.next(), path, queries);
            }
        } else {
            Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
            while (it.hasNext()) {
                Map.Entry<String, JsonNode> entry = it.next();
                if (org.springframework.util.StringUtils.hasText(path)) {
                    buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
                } else {  // 根节点
                    buildQuery(entry.getValue(), entry.getKey(), queries);
                }
            }
        }
    }
}
